import cgi
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db
import models
import scheduler
import os
from google.appengine.ext.webapp import template
import logging
import sys
sys.path.append("python-graph/")
import graph
import types
from google.appengine.api import urlfetch
import urllib
import datetime
import time
import random
class MainPage(webapp.RequestHandler):
	def get(self):
		#this is for http_load
		ispost = self.request.get("post")
		if ispost == "true":
			self.post()
		else:
			tid=None
			template_values={}
			if self.request.get("action") == "init":
				path = os.path.join(os.path.dirname(__file__), 'index.html')
			else:
				path = os.path.join(os.path.dirname(__file__), 'main.html')
			self.response.out.write(template.render(path,template_values))
		"""if (self.request.cookies.has_key("transid")):
			tid=self.request.cookies["transid"]
		else:
			logging.info( "Will have to generate new value")
		template_values={}
		if tid is not None:
			#cookie already present
			logging.info( "Cookie is present")
		else:
			models.increment(name="transactionid")
			tid = models.get_count(name="transactionid")
			self.response.headers.add_header("Set-Cookie",("transid=%d" % int(tid)) ) 
		"""
		#set 
		#template_values["transactionid"] = tid
			
			

	def post(self):
		op=self.request.get("opn")
		tid = int(self.request.get("txn"))
		din=self.request.get("key")
		div=self.request.get("value")
		contenttype = self.request.get("ct")
		template_values={}
		template_values["transactionid"] = tid
		if op is not None and tid is not None:
			if op == "r" or op == "w":
				logging.info("Read or write operation")
				template_values["din"]=din
				template_values["div"]=div
				template_values["msg"]="Operation Done"
			else:
				logging.info("Commit or abort operation")
			returnval = scheduler.performop(op,tid,din,div)
			if returnval is not None:
				template_values["msg"] = ("Result of performing %s on %s with value %s by transaction %d = %s" % (op,din,div,tid,returnval))
			else: 
				template_values["msg"] = "Couldnt perform op, put in the wait queue"
		else:
			template_values("Error, either op or tid is none")
		if contenttype is not None and contenttype == "text":
			self.response.out.write(template_values["msg"])
		else:
			#fetch transaction log for this transaction
			t = models.Transactions.gql("WHERE tid = :1",tid).get()
			
			if t and t.ops:
				logging.info("found operations")
				operations=[]
				for opkey in t.ops:
					operations.append(models.Operations.get(opkey))
				template_values["operations"] = operations
			else:
				if not t:
					logging.info("transaction not found")
				elif not t.ops:
					logging.info("No ops")
			self.rendertemplate(template_values)
		
	def rendertemplate(self,template_values,filename="index.html"):
		path = os.path.join(os.path.dirname(__file__), filename)
		self.response.out.write(template.render(path,template_values))
		
class OCCLock(webapp.RequestHandler):
	def get(self):
		ispost = self.request.get("post")
		if ispost == "true":
			self.post()
		else:
			self.rendertemplate({})
	def post(self):
		op=self.request.get("opn")
		tid = int(self.request.get("txn"))
		din=self.request.get("key")
		div=self.request.get("value")
		template_values={"transactionid":tid}
		if op is not None and tid is not None:
			if op == "r" or op == "w":
				logging.info("Read or write operation")
				template_values["din"]=din
				template_values["div"]=div
				template_values["msg"]="Operation Done"
			else:
				logging.info("Commit or abort operation")
			returnval = scheduler.OCCSchedule(op,tid,din,div)
			contenttype = self.request.get("ct")
			if returnval:
				template_values["msg"] = ("Result of performing %s on %s with value %s by transaction %d = %s" % (op,din,div,tid,returnval))
			elif op == "a":
				template_values["msg"] = "Transaction Aborted"
			else: 
				template_values["msg"] = "Couldn't perform op. There was a conflict detected. Aborting Transaction"
		else:
			template_values("Error, either op or tid is none")
			
		if contenttype is not None and contenttype == "text":
			#fetch operations for this transaction
			
			self.response.out.write(template_values["msg"])
		else:
			template_values["seqno"] = tid
			operations=[]
			transaction = models.OCCTrans.gql("WHERE sno = :1",tid).get()
			template_values["transaction"] = transaction
			if transaction:
				logging.info("found transaction")
				for op in models.OCCOperations.gql("WHERE trans = :1",transaction):
					operations.append(op)
				template_values["operations"] = operations
			else:
				logging.info("transaction not found")
			self.rendertemplate(template_values)
		
			
			
	def rendertemplate(self,template_values,filename="indexocc.html"):
		path = os.path.join(os.path.dirname(__file__), filename)
		self.response.out.write(template.render(path,template_values))
			
class Admin(webapp.RequestHandler):
	def get(self):
		logging.info("im here")
		logging.info(self.request.path)
		template_values={}
		if self.request.path == "/admin/detectDeadlock":
			self.detectDeadlocks()		
		elif self.request.path == "/admin/showss2pl":
			self.showss2pltransactions()
		elif self.request.path == "/admin/showwaitingss2pl":
			self.showss2pltransactions(True)			
		elif self.request.path == "/admin/dataitems":
			self.dataitems()
		elif self.request.path == "/admin/cfg":
			self.cfg()							
		else:
			self.rendertemplate(template_values,"admin.html")
		
	def post(self):
		models.unlocklocktable();
		self.get()
		
	def rendertemplate(self,template_values,filename="admin.html"):
		path = os.path.join(os.path.dirname(__file__), filename)
		self.response.out.write(template.render(path,template_values))	
	def detectDeadlocks(self):
		ipadd = self.request.remote_addr
		returndict = scheduler.detectDeadlock()
		cycle=None
		if(returndict.has_key("cycle")):
			cycle = returndict["cycle"]
		template_values = {}
		if returndict.has_key("dot"):
			template_values["dot"] = returndict["dot"]
			params={}
			params["dot"] = returndict["dot"]
			params["imgfile"] = str(random.randint(0,10))+"deadlock.png"
			s=urllib.urlencode(params)
			result = urlfetch.fetch(url="http://"+ipadd+"/puneet274/index",payload=s,method=urlfetch.POST)
			template_values["imgurl"] = result.content
		if cycle:
			template_values["msg"] = "Deadlock found. Cycle exists between %s " % ("-".join(map(str,cycle)))
		else:
			template_values["msg"] = "No cycle"
		self.rendertemplate(template_values,"deadlock.html")
	def cfg(self):
		stype = self.request.get("type")
		ipadd = self.request.remote_addr
		returndict = scheduler.getcfg(stype)
		template_values={"cfg":True}
		if returndict and returndict.has_key("dot"):
			template_values["dot"] = returndict["dot"]
			params={}
			params["dot"] = returndict["dot"]
			params["imgfile"] = str(random.randint(0,10))+"cfg.png"
			s=urllib.urlencode(params)
			result = urlfetch.fetch(url="http://"+ipadd+"/puneet274/index",payload=s,method=urlfetch.POST)
			template_values["imgurl"] = result.content
		self.rendertemplate(template_values,"deadlock.html")
			
	def showss2pltransactions(self,onlywaiting=False):
		transactions = models.Transactions.all()
		showtransactions = []
		for t in transactions:			
			trans = {}
			if t and t.ops:
				logging.info("found operations")
				operations=[]
				for opkey in t.ops:
					op = models.Operations.get(opkey)
					if (onlywaiting and op.iswaiting) or (not onlywaiting):
						operations.append(op)
				if operations:
					trans["operations"]= operations
					trans["tid"] = t.tid
					showtransactions.append(trans) 
			else:
				if not t:
					logging.info("transaction not found")
				elif not t.ops:
					logging.info("No ops")
		template_values={}
		template_values["transactions"] = showtransactions
		self.rendertemplate(template_values,"showss2pltransactions.html")
	def dataitems(self):
		template_values = {}
		dataitems=[]
		for di in models.DataItems.all():
			logging.info("Addiing dataitem: %s val: %s" %(di.din,di.div))
			dataitems.append(di)
		template_values["dataitems"] = dataitems
		self.rendertemplate(template_values,"dataitems.html")
		
class Histories(webapp.RequestHandler):
	def get(self):
		type=self.request.get("type")
		if type == "OCC":
			self.occhistories()
		elif type == "SS2PL":
			self.ss2plhistories()
	def occhistories(self):
		template_values = {}
		template_values["type"] = "OCC"
		template_values["logrecords"]=[logrecord for logrecord in models.OCCLog.all().order("la")]
		self.rendertemplate(template_values)
	def ss2plhistories(self):
		template_values = {}
		template_values["type"] = "SS2PL"
		template_values["logrecords"]=[logrecord for logrecord in models.Log.all().order("la")]		
		self.rendertemplate(template_values)
		
	def rendertemplate(self,template_values,filename="histories.html"):
		path = os.path.join(os.path.dirname(__file__), filename)
		self.response.out.write(template.render(path,template_values))				
		
class DataStore(webapp.RequestHandler):
	def get(self):
		if self.request.get("action")=="clearget":
			self.clearget()
		else:
			self.rendertemplate({})
	def post(self):
		logging.info("post clear ds.")
		if self.request.get("action")=="cp":
			self.cleards()
		else:
			self.rendertemplate({})
	def cleards(self):
		logging.info("cleards called")
		logging.info("Clearing model"+self.request.get("model"))
		model = self.request.get("model")
		exec("ls="+model+".all()")
		for l in ls:
			l.delete()
		
	def clearget(self):
		dic = models.__dict__
		classes = {}
		for item in dic:
			obj = dic[item]
			if(hasattr(obj,"__mro__")):
				cname = str(obj.__mro__)
				#print cname
				fqn=cname[cname.index("'")+1:cname.index("'")+1+cname[cname.index("'")+1:].index("'")]
				
				exec("ls="+fqn+".all()")
				i=0
				for l in ls:
					i=i+1
				classes[fqn]=i
		#print "hello"
		print classes
		template_values={}
		template_values["models_list"] = classes
		self.rendertemplate(template_values,"cleardatastore.html")
	def rendertemplate(self,template_values,filename="datastore.html"):
		path = os.path.join(os.path.dirname(__file__), filename)
		self.response.out.write(template.render(path,template_values))				
class ResponseWriter:
	@staticmethod
	def rendertemplate(response,template_values,filename):
		path = os.path.join(os.path.dirname(__file__), filename)
		response.out.write(template.render(path,template_values))				
		
class Reports(webapp.RequestHandler):
		def get(self):
			logging.info("Handling reports")
			action = self.request.get("action")
			if action == "tcmplt":
				self.transactionCompleteTime()
			elif action == "aborts":
				self.aborts()
			elif action == "waittimes":
				self.ss2plwaitttime()
				
		def transactionCompleteTime(self):
			stype=self.request.get("type")
			tmin=sys.maxint
			tmax=-1.0
			avg=0.0
			ctr=0
			tsum=0.0
			iterablelist = []
			if stype == "ss2pl":
				logging.info("trying to fetch ss2pl ts")
				iterablelist = models.Transactions.gql("WHERE isaborted = :1 and endtime != :2",False,None)
			elif stype=="occ":
				iterablelist = models.OCCTrans.gql("WHERE phase = :1 and endtime != :2","comitted",None)
			if not iterablelist:
				logging.info("No Transactions found")
			for t in iterablelist:
				ctr = ctr+1
				timedelta = (t.endtime-t.starttime)
				timediff = timedelta.days * 24*60*60*1000.0 + timedelta.seconds*1000.0 + (timedelta.microseconds)/1000.0
				logging.info("timediff is: %f"%timediff)
				tsum=tsum+timediff
				if timediff > tmax:
					tmax=timediff
				if timediff < tmin:
					tmin=timediff
			if ctr > 0:
				avg = tsum/ctr
			if tmin == sys.maxint:
				tmin=0
			if tmax == -1:
				tmax=0
			template_values = {"min" : tmin,"max":tmax,"avg":avg,"ctr":ctr}
			ResponseWriter.rendertemplate(self.response, template_values,"completetimes.html")
			
		
		def aborts(self):
			stype=self.request.get("type")
			template_values={}
			if stype=="ss2pl":
				#in this case its just the user aborted transactions. restricted to 999 by google
				template_values["cntuser"]= models.Transactions.all().filter("isaborted = ",True).count()
			elif stype=="occ":
				logging.info("occ count")
				template_values["cntuser"]=models.OCCTrans.all().filter("isuseraborted = ",True).count()
				template_values["cntssytem"]=models.OCCTrans.gql("WHERE phase = :1 and isuseraborted = :2","aborted",False).count()
				logging.info(template_values["cntssytem"])
			ResponseWriter.rendertemplate(self.response, template_values,"aborts.html")
		def ss2plwaitttime(self):	
			stype=self.request.get("type")
			tmin=sys.maxint
			tmax=-1
			avg=0.0
			ctr=0
			tsum=0.0
			iterablelist = []
			if stype == "ss2pl":
				iterablelist = models.Operations.gql("WHERE  optype IN :1 and waitendtime != :2",["r","w","c"],None)
			#makes sense only for occ
			for t in iterablelist:
				if t.waitstarttime is None:
					continue
				ctr = ctr+1
				timedelta = t.waitendtime - t.waitstarttime
				timediff = timedelta.days * 24*60*60*1000 + timedelta.seconds*1000.0 + (timedelta.microseconds)/1000.0
				tsum=tsum+timediff
				if timediff > tmax:
					tmax=timediff
				if timediff < tmin:
					tmin=timediff
			if ctr > 0:	
				avg = tsum/ctr
			if tmin == sys.maxint:
				tmin=0
			if tmax == -1:
				tmax=0
			template_values = {"min" : tmin,"max":tmax,"avg":avg}
			ResponseWriter.rendertemplate(self.response, template_values,"ss2plwaittimes.html")
class SS2PLDeadlockAbort(webapp.RequestHandler):
	#aborts all transactions with waiting ops where wait time is greater than 20 seconds
	def get(self):
		currenttime = datetime.datetime.now()
		killedtransactions = []
		done = False
		while not done:
			try: 
				for op in models.getallwaitingops(None):
					if(op.waitstarttime):
						timedelta = currenttime-op.waitstarttime
						timediff = timedelta.days * 24*60*60*1000 + timedelta.seconds*1000.0 + (timedelta.microseconds)/1000.0
						logging.error("Time diff = "+str(timediff))
						if timediff > 20000 and op.transaction.tid not in killedtransactions:
							scheduler.performop("a",op.transaction.tid,None,None)
							killedtransactions.append(op.transaction.tid)
					else:
						logger.error("waiitng op doesnt have wait start time")
				done = True
			except:
				logging.error("Error Occured. Retrying")
		self.response.out.write("No of Killed Transactions = " + str(len(killedtransactions)))
		
		
application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                      ('/addTransaction', MainPage),
                                      ('/addOCCTrans', OCCLock),
                                      ('/admin', Admin),
                                      ('/admin/', Admin),
                                      ('/admin/showss2pl', Admin),
                                      ('/admin/showwaitingss2pl', Admin),
                                      ('/admin/detectDeadlock', Admin),
                                      ('/admin/resetlocktable', Admin),
                                      ('/admin/dataitems', Admin),
                                      ('/admin/cfg', Admin),
                                      ('/admin/histories', Histories),
                                      ('/admin/datastore', DataStore),
                                      ('/admin/reports', Reports),
                                      ('/admin/ss2plbreakdeadlock', SS2PLDeadlockAbort)],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()
